package cn.weixin.common.util;

import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.thoughtworks.xstream.mapper.MapperWrapper;

/**
 * 一个类型的消息请求始终只用到一个xstream对象
 * 
 * @author tongyichun
 * 
 */
public class XStreamFactory {

	protected static String PREFIX_CDATA    = "<![CDATA[";   
	protected static String SUFFIX_CDATA    = "]]>"; 
	
	private static XStreamFactory xStreamFactory = null;
	private Map<String, XStream> map = new HashMap<String, XStream>();
	private static final Object lock = new Object();

	private XStreamFactory() {

	}

	public static XStreamFactory getInstance() {
		if (xStreamFactory == null) {
			synchronized (lock) {
				if (xStreamFactory == null) {
					xStreamFactory = new XStreamFactory();
				}
			}
		}
		return xStreamFactory;
	}

	/**
	 * 从MAP中获取XStream对象
	 * 
	 * @param type
	 * @return
	 */
	public XStream createXStream(String type) {
		if (type == null || type.length() == 0) {
			type = "default";
		}
		XStream xStream = (XStream) map.get(type);
		if (xStream == null) {
			xStream = new XStream(new XppDriver() {
				public HierarchicalStreamWriter createWriter(Writer out) {
					return new PrettyPrintWriter(out) {
						protected void writeText(QuickWriter writer, String text) {
							writer.write(PREFIX_CDATA);  
		                    writer.write(text);  
		                    writer.write(SUFFIX_CDATA);
						}
					};
				}
			}){
				@Override
				protected MapperWrapper wrapMapper(MapperWrapper next){
					return new MapperWrapper(next) {
						@Override
						public boolean shouldSerializeMember(Class definedIn, String fieldName){
							if(definedIn == Object.class){
								try {
									return this.realClass(fieldName) != null;
								} catch (Exception e) {
									return false;
								}
							}else{
								return super.shouldSerializeMember(definedIn, fieldName);
							}
						}
					};
				}
			};
			map.put(type, xStream);
		}

		return xStream;
	}

}
